#include "Room.h"

#include "Character.h"

#include "../ConsoleColor.h"
#include <iostream>
#include <algorithm>

Room::Room(const std::string &name, const std::string &description) 
	: GameObject(name,description)
{
}

Room::~Room()
{
}

void Room::look() 
{ 
	//Room Title
	std::cout << green << name << white << std::endl;
	
	//Room description
	std::cout << description << std::endl;

	//List characters
	std::for_each(begin(characters), end(characters), [](const CharacterPtr &character)
	{
		if(character->hasPlayer() == false)
			character->look();
	});

	//List objects
	std::for_each(begin(objects), end(objects), [](const GameObjectPtr &object)
	{
		object->look();
	});

	//List exits
	std::cout << "Exits: ";
	unsigned int num_exits = exits.size();
	unsigned int exit_i = 0;
	std::for_each(begin(exits), end(exits), [&](const ExitPtr &exit)
	{
		std::cout << exit->getName();
		if(exit_i == num_exits-1)
			std::cout << "." << std::endl;
		else
			std::cout << ", ";
		exit_i++;
	});
}

void Room::update(unsigned int tick)
{
	//Update characters
	std::for_each(begin(characters), end(characters), [&](const CharacterPtr &character)
	{
		character->update(tick);
	});

	//Update objects
	std::for_each(begin(objects), end(objects), [&](const GameObjectPtr &object)
	{
		object->update(tick);
	});

	//Update exits
	std::for_each(begin(exits), end(exits), [&](const ExitPtr &exit)
	{
		exit->update(tick);
	});
}

GameObjectPtr Room::add(const GameObjectPtr &object)
{
	objects.push_back(object);
	return object;
}

void Room::remove(const GameObjectPtr &object)
{
	for(unsigned int i = 0; i < objects.size(); i++)
	{
		if(object->getName() == objects[i]->getName())
		{
			objects[i] = objects.back();
			objects.pop_back();
			break;
		}
	}
}

CharacterPtr Room::add(const CharacterPtr &character)
{
	characters.push_back(character);
	return character;
}

void Room::remove(const CharacterPtr &character)
{
	for(unsigned int i = 0; i < characters.size(); i++)
	{
		if(character->getName() == characters[i]->getName())
		{
			characters[i] = characters.back();
			characters.pop_back();
			break;
		}
	}
}

ExitPtr Room::add(ExitPtr exit)
{
	exits.push_back(exit);
	return exit;
}

void Room::remove(const ExitPtr &exit)
{
	for(unsigned int i = 0; i < exits.size(); i++)
	{
		if(exits[i]->getName() == exit->getName())
		{
			exits[i] = exits.back();
			exits.pop_back();
			return;
		}
	}
}

const ExitPtr &Room::getExit(Exit::ExitId direction)
{
	for(unsigned int i = 0; i < exits.size(); i++)
	{
		if(exits[i]->getDirection() == direction)
			return exits[i];
	}
	return null_exit;
}

void Room::enter(const CharacterPtr &character, const Exit::ExitId &from)
{
	if(character->hasPlayer())
		look();
	else
		std::cout << red << character->getName() << white << " has arrived from the " << Exit::getExitIdName(from) << std::endl;

	add(character);
}

void Room::exit(const CharacterPtr &character, const Exit::ExitId &to)
{
	if(character->hasPlayer() == false)
		std::cout << red << character->getName() << white << " leaves " << Exit::getExitIdName(to) << std::endl;
	remove(character);
}

void Room::enter(const GameObjectPtr &object, const Exit::ExitId &from)
{
	std::cout << yellow << object->getName() << white << " has arrived from the " << Exit::getExitIdName(from) << std::endl;
	add(object);
}

void Room::exit(const GameObjectPtr &object, const Exit::ExitId &to)
{
	std::cout << yellow << object->getName() << white << " leaves " << Exit::getExitIdName(to) << std::endl;
	remove(object);
}

void Room::add(Setting setting)
{
	settings.push_back(setting);
}

bool Room::has(Setting setting)
{
	for(unsigned int i = 0; i < settings.size(); i++)
	{
		if(settings[i] == setting)
			return true;
	}
	return false;
}
